import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;


public class SmartRobot {
	private StateMonitor tracker;
	private DecisionMaker maker;
	private double[]current=new double[DecisionMaker.NUM_FEATURES];
	private double[][]a=new double[DecisionMaker.NUM_FEATURES][DecisionMaker.NUM_FEATURES];
	private double[]b=new double[DecisionMaker.NUM_FEATURES];
	private double[]future=new double[DecisionMaker.NUM_FEATURES];
	private double[]omega=new double[DecisionMaker.NUM_FEATURES];

	public SmartRobot() {
		tracker = new StateMonitor(new Stateview());
		for(int i=0;i<DecisionMaker.NUM_FEATURES;i++){
			for(int k=0;k<DecisionMaker.NUM_FEATURES;k++){
				a[i][k]=0;
			}
		}
		for(int i=0;i<DecisionMaker.NUM_FEATURES;i++){
			b[i]=0;
		}
	}

	public DecisionMaker getDecisionMaker() {
		return maker;
	}

	public StateMonitor getStateMonitor() {
		return tracker;
	}
	// all calculation based on the current state
	public void observe() {
		maker = new DecisionMaker(tracker.generateStates());
	}

	// need to be implemented
	// considering the future state
	public void think() {
	}
	public void recordcurrent(Stateview s){

		current=this.getDecisionMaker().learncompute(s);
		//System.out.println(current[3]);
	}


	public void recordfuture( Stateview s){
		future=this.getDecisionMaker().learncompute(s);
	}


	public void learn(){
		double temp[]=new double[DecisionMaker.NUM_FEATURES];

		for(int i=0;i<DecisionMaker.NUM_FEATURES;i++){
			temp[i]=current[i]-0.2*future[i];
			//System.out.println(temp[i]);
		}

		for(int i=0;i<DecisionMaker.NUM_FEATURES;i++){
			for(int k=0;k<DecisionMaker.NUM_FEATURES;k++){
				a[i][k]+=current[i]*temp[k];
			}
		}
		for(int i=0;i<DecisionMaker.NUM_FEATURES;i++){
			b[i]+=10*current[i];
		}

		// print a matrix and b matrix
		/*
		System.out.println("A matrix:");
		for(int i=0;i<DecisionMaker.NUM_FEATURES;i++){
			for(int k=0;k<DecisionMaker.NUM_FEATURES;k++){
				System.out.print(a[i][k] + " ");
			}
			System.out.println();
		}
		System.out.println("b matrix:");
		for(int i=0;i<DecisionMaker.NUM_FEATURES;i++){
			System.out.println(b[i]);
		}*/

	}

	public void printOmega(int rowsCleared) {
		try {
			String out_f = "omega.txt";
			String log = "log.txt";
			FileWriter fw = new FileWriter(out_f);
			BufferedWriter bw = new BufferedWriter(fw);
			BufferedWriter bw2 = new BufferedWriter(new FileWriter(log, true));
			
			System.out.println("A matrix:");
			for(int i=0;i<DecisionMaker.NUM_FEATURES;i++){
				for(int k=0;k<DecisionMaker.NUM_FEATURES;k++){
					System.out.print(a[i][k] + " ");
				}
				System.out.println();
			}
			System.out.println("b matrix:");
			for(int i=0;i<DecisionMaker.NUM_FEATURES;i++){
				System.out.println(b[i]);
			}
			inverseMatrix(a);
			System.out.println("inverse of A matrix:");
			for(int i=0;i<DecisionMaker.NUM_FEATURES;i++){
				for(int k=0;k<DecisionMaker.NUM_FEATURES;k++){
					System.out.print(a[i][k] + " ");
				}
				System.out.println();
			}

			double tmp = 0;
			System.out.println("print omega: ");
			for(int i=0;i<DecisionMaker.NUM_FEATURES;i++){
				tmp = 0;
				for(int j=0;j<DecisionMaker.NUM_FEATURES;j++) {
					tmp += a[i][j] * b[j];
				}
				omega[i] = tmp;
				try {
					bw.write(omega[i]+" \r\n");
					bw2.write(omega[i]+" ");
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(omega[i]);
			}
			bw2.write("\r\n");
			bw2.write(rowsCleared + "\r\n");
			bw.close();
			bw2.close();
			fw.close();
			
		} catch(Exception e) {
			e.printStackTrace();
		}
	}

	public static void inverseMatrix(double[][] a) {
		int i, j, k, m;
		double temp;

		int numRows = a.length;
		int numCols = a[0].length;
		int index[][] = new int[numRows][2];
		partialPivot(a, new double[numRows], index);
		for (i = 0; i < numRows; ++i) {
			temp = a[i][i];
			for (j = 0; j < numCols; ++j) {
				a[i][j] /= temp;
			}

			a[i][i] = 1.0 / temp;
			for (k = 0; k < numRows; ++k) {
				if (k != i) {
					temp = a[k][i];
					for (j = 0; j < numCols; ++j) {
						a[k][j] -= temp * a[i][j];
					}
					a[k][i] = -temp * a[i][i];
				}
			}
		}
		for (j = numCols - 1; j >= 0; --j) {
			k = index[j][0];
			m = index[j][1];
			if (k != m) {
				for (i = 0; i < numRows; ++i) {
					temp = a[i][m];
					a[i][m] = a[i][k];
					a[i][k] = temp;
				}
			}
		}
	}

	public static void partialPivot(double mt[][], double v[], int index[][]) {
		double temp;
		double tempRow[];
		int i, j, m;
		int numRows = mt.length;
		int numCols = mt[0].length;
		double scale[] = new double[numRows];
		for (i = 0; i < numRows; ++i) {
			index[i][0] = i;
			index[i][1] = i;
			for (j = 0; j < numCols; ++j) {
				scale[i] = Math.max(scale[i], Math.abs(mt[i][j]));
			}
		}
		for (j = 0; j < numCols - 1; ++j) {
			m = j;
			for (i = j + 1; i < numRows; ++i) {
				if (Math.abs(mt[i][j]) / scale[i] >
				Math.abs(mt[m][j]) / scale[m]) {
					m = i;
				}
			}
			if (m != j) {
				index[j][0] = j;
				index[j][1] = m;
				tempRow = mt[j];
				mt[j] = mt[m];
				mt[m] = tempRow;
				temp = v[j];
				v[j] = v[m];
				v[m] = temp;
				temp = scale[j];
				scale[j] = scale[m];
				scale[m] = temp;
			}
		}
	}

	public static void main(String[] args) throws IOException {

		int min = 100000, max = 0, ave = 0;
		int numTimes = 1;
		State s = new State();
		Stateview s1= new Stateview();
		SmartRobot p = new SmartRobot(); 
		for(int i = 0; i < numTimes; i++){
			s1.setTop(s.getTop());
			// copy field
			s1.setField(s.getField());
			// copy piece
			s1.setPiece(s.getNextPiece());

			s1.setPreRowsClear(s.getRowsCleared());

			// comment this if you do not want this frame to show
			new TFrame(s);
			// create a robot!!!!!
			// copy piece
			p.getStateMonitor().getState().setPiece(s.getNextPiece());

			while(!s.hasLost()) {
				p.observe();
				p.think();
				p.recordcurrent(s1);
				//int move[] = p.getDecisionMaker().getDecision();
				int move[] = p.getDecisionMaker().minimaxFunction();

				//System.out.println("orient: " + move[0] + "; slot: " + move[1]);

				//p.getStateMonitor().getState().makeMove(move[0], move[1]);

				s1.makeMove(move[0], move[1]);
				s.makeMove(move[0], move[1]);
				p.recordfuture(s1);
				//p.learn();
				// copy the state to monitor
				// copy top

				s1.setTop(s.getTop());
				// copy field
				s1.setField(s.getField());
				// copy piece
				s1.setPiece(s.getNextPiece());

				s1.setPreRowsClear(s.getRowsCleared());


				p.getStateMonitor().getState().setTop(s.getTop());
				// copy field
				p.getStateMonitor().getState().setField(s.getField());
				// copy piece
				p.getStateMonitor().getState().setPiece(s.getNextPiece());

				//p.pickMove(s,s.legalMoves());
				// comment the below two lines if no animation is shown
				s.draw();
				s.drawNext(0,0);
				/*
				try {
					Thread.sleep(0);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}*/
			}
			System.out.println("You have completed "+s.getRowsCleared()+" rows.");

			//p.printOmega(s.getRowsCleared());
			/*
		int cleared = s.getRowsCleared();

		if(cleared > max) max = cleared;
		if(cleared < min) min = cleared;
		ave += cleared;
		}
		ave /= numTimes;*/
			/*
		System.out.println("Max: " + max + ", Min: " + min + ", Ave: " + ave);
		for(int z=0;z<p.getDecisionMaker().omega.length; z++){
			System.out.println(" "+p.getDecisionMaker().omega[z]+" ");

		}*/
		}
	}
}
